/**
 * @main
 * Plik z definicjami klasy Wielomian i funkcji pomocnicznych, zadeklarowanych w
 * w pliku naglowkowym wielomian.h.
 * @file    wielomian.cpp
 * @author  Grzegorz Sejnota
 *
 * @created on 22 listopad 2008, 22:24
 * @version 0.0001
 */

#include "wielomian.h"
#include <string>
#include <iostream>
#include <iomanip>
#include <cmath>
using namespace std;

//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++ POCZĄTEK  [klasy wielomian] +++++++++++++++++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//==============================================================================
/** bezargumentowy konstruktor wielomianu pustego.
 */
Wielomian :: Wielomian(){}

//==============================================================================
/** destruktor
 */
Wielomian :: ~Wielomian(){}

//==============================================================================
/** konstruktor wielomianu o rozmiarze stopien wypelniajac go wartoscią
 *
 *      @param stopien - stopien wielomianu
 *      @param wartosc - wartosc wspolczynników wielomianu
 */
 Wielomian :: Wielomian(int stopien, double wartosc){
     this->stopien = stopien; 
     wspolczynniki.reserve(stopien+1);
     wspolczynniki.assign(stopien+1, wartosc);
 }
 
//==============================================================================
/** konstruktor konwertujący z typu double
  * tworzy wielomian zerowego stopnia o wartości podanej w wspA0
  *
  *      @param wspA0 - współczynnik przy zerowej potedze
  */
 Wielomian :: Wielomian(double wspA0){
     wspolczynniki.push_back(wspA0);
     stopien = 0;
 }
 
 
//==============================================================================
/** konstruktor tworzacy wielomian z tablicy double o rozmiarze stopien
  *
  *      @param *tablica - wskaźnik do tablicy ze współczynnikami
  *      @param stopien - stopien wielomianu, ilosc elementów z tablicy będącymi
  *                wspolczynnikami wielomianu, w kolejnosci malejącej tzn.
  *                pierwszy element tablicy jest współczynnikiem przy najwyższej 
  *                potędze
  */
 Wielomian :: Wielomian(int stopien, double *tablicaWsp){
     this->stopien = stopien;
     for( int i=0; i <= stopien; ++i){
         wspolczynniki.push_back(*(tablicaWsp+i));
     }
 }
 
//============================================================================== 
/** konstruktor tworzący wielomian z wektora współczynników
  *  
  *      @param wektorWsp - wektor współczynników
  */
 Wielomian :: Wielomian( vector<double> &wektorWsp){
     stopien = wektorWsp.size()-1;
     wspolczynniki = wektorWsp;
 }

 
 
//============================================================================== 
/**  konstruktor kopiujący
  *
  *      @param &wzor - referencja do obiektu klasy Wielomian, który ma być skopiowany
  */
 Wielomian :: Wielomian ( const Wielomian &wzor ){
     //cout<<"kopiujacy";
     stopien = wzor.stopien;
     wspolczynniki = wzor.wspolczynniki;
 }
 
//============================================================================== 
/**  publiczna funkcja skladowa klasy Wielomian usuwająca zbedne zera
  * funkcja usuwa zera przy najwyższych potęgach, obniżając stopien wielomianu
  *
  */
 void Wielomian :: usunZera(){           
    vector<double> :: iterator it=wspolczynniki.begin();           
    for(int i=stopien; i >= 0; i--){
        if((*this)[i] == 0){
            it++;
        }else{
            break;
        }
    }
    wspolczynniki.erase(wspolczynniki.begin(), it);
    stopien = wspolczynniki.size()-1;      
 }
 
//============================================================================== 
/**  funkcja przeładowanego operatora przypisania =
  *
  *     @param wzor - wielomian który ma być przypisany
  *     @param wskaźnik do wielomianu wynikowego (do którego przypisano wzor)
  */
Wielomian& Wielomian :: operator=(const Wielomian &wzor ){
    //cout<< "przypisanie";
    if( this== &wzor )return *this;
    this->stopien = wzor.stopien;
    //cout<<" przypisanie stopien"<<stopien<<wzor.stopien<<endl;
    this->wspolczynniki = wzor.wspolczynniki;
    //cout<< "przypisanie koniec";
    return *this;
}
 

//============================================================================== 
/** funkcja przeładowanego operatora nawiasowego
  * zwracająca wartość wielomianu dla podanego argumentu. wartość jest obliczana
  * przy użyciu schematu hornera.
  *
  *      @param argument - liczba dla której ma być wyznaczona wartość wielomianu
  *      @return wartość wielomianu w(argument)
  */
double Wielomian :: operator()( double argument ) const{
     double wynik = 0;
     for (int i=0; i<=stopien; i++){
         wynik = wspolczynniki.at(i) + wynik * argument;
     }
     //wynik += this->wspolczynniki.at(stopien);
     return wynik;
 }
 
//============================================================================== 
/** funkcja przeładowanego operatora nawiasowego dla argumentów zespolonych
  * zwracająca zespoloną wartość wielomianu dla podanego zespolonego argumentu. 
  * wartość jest obliczana przy użyciu schematu hornera.
  *
  *      @param argument - liczba dla której ma być wyznaczona wartość wielomianu
  *      @return wartość wielomianu w(argument)
  */
complex<double> Wielomian :: operator()( complex<double> argument ) const{
     complex<double> wynik(0.0,0.0);
     for (int i=0; i<=stopien; i++){
         wynik = wspolczynniki.at(i) + wynik * argument;
     }
     //wynik += this->wspolczynniki.at(stopien);
     return wynik;
 }
 
 
//============================================================================== 
/** funkcja przeładowanego operatora tablicowego
  * zwracająca wspołczynnik wielomianu przy potedze wspIndex. Umożliwia także
  * nadpisanie tego współczynnika (może stanowić L - wartość)
  *
  *     @param wspIndex - indeks wspolczynnika wielomianu (wykładnik potęgi) który ma być
  *                pobrany (nadpisany)
  *     @return wskaźnik do współczynnika przy potędze wspIndex
  */
double & Wielomian :: operator[]( unsigned int wspIndex){
     return this->wspolczynniki.at(this->stopien - wspIndex);
 }
 
 
//============================================================================== 
/**  przeładowany operator += 
  *  dodaje do wielomianu inny wielomian i zwraca wskaźnik do wielomianu 
  *  wynikowego
  *
  *      @param wielomian - wielomian, który ma zostać dodany
  *      @return wielomian wynikowy (*this + wielomian)
  */
 Wielomian Wielomian :: operator+=( const Wielomian & w){
     *this = *this + w;
     return *this;
 }
               
//============================================================================== 
/**  przeładowany operator -= 
  *  odejmuje do wielomianu *this inny wielomian i zwraca wskaźnik do wielomianu 
  *  wynikowego
  *
  *      @param wielomian - wielomian, który ma zostać odjęty
  *      @return wielomian wynikowy (*this + wielomian)
  */
Wielomian Wielomian :: operator-=( const Wielomian & w){
     *this = *this - w;
     return *this;
 }

//============================================================================== 
/**  przeładowany operator *= 
  *  mnoży wielomian *this przez wielomian w i zwraca wskaźnik do wielomianu 
  *  wynikowego
  *
  *      @param w - wielomian czynnikowy
  *      @return wielomian wynikowy (*this * wielomian)
  */
Wielomian Wielomian :: operator*=( const Wielomian & w){
    *this = (*this) * w;
    return *this;
}
    
//============================================================================== 
/**  przeładowany operator /= 
  *  dzieli wielomian *this przez wielomian w i zwraca wskaźnik do wielomianu 
  *  wynikowego
  *
  *      @param w - wielomian dzielnikowy
  *      @return wielomian wynikowy (*this / w)
  */
Wielomian Wielomian :: operator/=( const Wielomian & w){
    *this = (*this) / w;
    return *this;
}

//============================================================================== 
/** funkcja tworząca wielomian z postaci iloczynowej. podajemy stopien i pierwiastki
  * z klawiatury. funkcja zwraca wielomian w postaci współczynnikowej.
  *
  *     @return wielomian o miejscach zerowych podanych z klawiatury
  */
Wielomian  postacIloczynowa(){
    int stopien;
    double x;
    cout<< "Podaj stopien wielomianu, ktory mam utworzyc:" <<endl;  
    cout<< "\tstopien = "; cin>> stopien;   //wczytanie stopnia wielomianu
    vector<double> pierwiastki,
                   wspObecne(stopien+1, 0.0),
                   wspPoprzednie(stopien+1, 0.0);
    
     //-------------------------------------------------------------------------
     // pobranie pierwiastków wielomianu z klawiatury
     //-------------------------------------------------------------------------
    for (int i = 1; i<=stopien; i++){   //wczytanie pierwiastków wielomianu
        cout<< "\tx1 = "; cin>> x;
        pierwiastki.push_back(-x);  //zapisujemy pierwiastek ze znakiem ujemnym
    }
     //-------------------------------------------------------------------------
     // wypisanie postaci iloczynowej
     //-------------------------------------------------------------------------
    cout<< endl<<"postac iloczynowa:"<<endl;    
    cout<< "\tw(x) = ";
    for (int i = 0; i<stopien; i++){    //pętla po ilości pierwiastków
        cout<< "(x ";
        if(pierwiastki[i] >= 0){
            cout<< "+ " <<pierwiastki[i]<<")";
        }else{
            cout<< "- " <<abs(pierwiastki[i])<<")";
        }
    }
    //--------------------------------------------------------------------------
    // obliczenie wspolczynnikow wielomianu
    //--------------------------------------------------------------------------
    wspObecne[stopien] = 1.0;
    for (int i = 0; i <stopien; i++){  //pętla po ilości pierwiastków
        wspPoprzednie = wspObecne;
        for(int k = stopien; k >= stopien-i-1; k--){    //pętla po wspołczynnikach
            //wspolczynniki w vectorach zapisane w sposob następujący:
            // vector[0] -> wsp przy najwyższej potędze
            
            if ( k != stopien-i-1 && k != stopien ){    //wspolczynnik nie w najwyższej potędze
                                                        //ani w najniższej
                wspObecne[k] = wspPoprzednie[k]*pierwiastki[i] 
                                        + wspPoprzednie[k+1];   //obliczenie wartości wsp
                                                                //jako anOb = anPop*pierw(i) + an-1Pop
            }else if( k == stopien){    //współczynnik a0
                wspObecne[k] = wspPoprzednie[k]*pierwiastki[i]; //obliczenie a0:
                                                                //jako anOb = a0Pop*pierw(i)
            }else if( k == stopien-i-1){    //wspolczynnik an
                wspObecne[k] = wspPoprzednie[k+1];  //obliczenie an:
                                                    //jako anOb = an-1Pop
            }
            cout<<"\t"<<wspObecne[stopien-k];
        }
        cout<<endl;
    }
    //-------------------------------------------------------------------------
    // utworzenie wielomianu w postaci współczynnikowej
    //-------------------------------------------------------------------------
    Wielomian w(wspObecne); //utworzenie wielomianu w z wektora wspObecne
    cout<< endl <<"Wielomian w postaci wspolczynnikowej:" <<endl;
    w.wypisz();
    cout<<endl;
    return w;
}

//============================================================================== 
/** funkcja tworząca wielomian z postaci iloczynowej. wektor pierwiastków podany
  * jako argument.
  *
  *     @param pierwiastki - wektor pierwiastkow
  *     @return wielomian o miejscach zerowych podanych z klawiatury
  */
Wielomian  postacIloczynowa( vector<double> pierwiastki){
    int stopien = pierwiastki.size();
    cout<<stopien<<pierwiastki.size();
    vector<double> wspObecne(stopien+1, 0.0),
                   wspPoprzednie(stopien+1, 0.0);
    
     //-------------------------------------------------------------------------
     // wypisanie postaci iloczynowej
     //-------------------------------------------------------------------------
    cout<< endl<<"postac iloczynowa:"<<endl;    
    cout<< "\tw(x) = ";
    for (int i = 0; i<stopien; i++){    //pętla po ilości pierwiastków
        cout<< "(x ";
        pierwiastki[i] = -pierwiastki[i];
        if(pierwiastki[i] >= 0){
            cout<< "+ " <<pierwiastki[i]<<")";
        }else{
            cout<< "- " <<abs(pierwiastki[i])<<")";
        }
    }
    //--------------------------------------------------------------------------
    // obliczenie wspolczynnikow wielomianu
    //--------------------------------------------------------------------------
    wspObecne[stopien] = 1.0;
    for (int i = 0; i <stopien; i++){  //pętla po ilości pierwiastków
        wspPoprzednie = wspObecne;
        for(int k = stopien; k >= stopien-i-1; k--){    //pętla po wspołczynnikach
            //wspolczynniki w vectorach zapisane w sposob następujący:
            // vector[0] -> wsp przy najwyższej potędze
            
            if ( k != stopien-i-1 && k != stopien ){    //wspolczynnik nie w najwyższej potędze
                                                        //ani w najniższej
                wspObecne[k] = wspPoprzednie[k]*pierwiastki[i] 
                                        + wspPoprzednie[k+1];   //obliczenie wartości wsp
                                                                //jako anOb = anPop*pierw(i) + an-1Pop
            }else if( k == stopien){    //współczynnik a0
                wspObecne[k] = wspPoprzednie[k]*pierwiastki[i]; //obliczenie a0:
                                                                //jako anOb = a0Pop*pierw(i)
            }else if( k == stopien-i-1){    //wspolczynnik an
                wspObecne[k] = wspPoprzednie[k+1];  //obliczenie an:
                                                    //jako anOb = an-1Pop
            }
            cout<<"\t"<<wspObecne[stopien-k];
        }
        cout<<endl;
    }
    //-------------------------------------------------------------------------
    // utworzenie wielomianu w postaci współczynnikowej
    //-------------------------------------------------------------------------
    Wielomian w(wspObecne); //utworzenie wielomianu w z wektora wspObecne
    cout<< endl <<"Wielomian w postaci wspolczynnikowej:" <<endl;
    w.wypisz();
    cout<<endl;
    return w;
}

//============================================================================== 
/**  funkcja wyznaczająca współczynniki k-tej pochodnej wielomianu
  *  
  *      @param rzadPochodnej - rząd pochodnej
  *      @return wielomian, bedacy pochodna wielomianu this
  */
Wielomian Wielomian :: pochodna( int rzadPochodnej) const{
    Wielomian wPochodna(*this);
    for (int k=0; k<rzadPochodnej; k++){    //pętla po rzędzie pochodnej
        for( int i=wPochodna.pobierzStopien(); i>0; i--){   //petla po wsp wielomianu
            wPochodna.wspolczynniki.at(i) = (wPochodna.pobierzStopien()-i+1)*wPochodna.wspolczynniki.at(i-1);
                        //obliczenie wspolczynnika przy pochodnej 
            //cout<<"a"<<wPochodna.pobierzStopien()-i<< "=" <<wPochodna.wspolczynniki.at(i);
        }
        wPochodna.wspolczynniki.at(0) = 0.0;    //obniżenie rzędu wielomianu
        wPochodna.usunZera();   //usunięcie zer
    }
    return wPochodna;
}

//============================================================================== 
/**  funkcja normalizujaca wspolczynniki wielomianu.
  *  
  *      @param wspNormalizacji - liczba przez ktora dzielone sa wszystkie 
 *                                wsp wielomianu
  *      @return wielomian unormowany
  */
Wielomian Wielomian :: normalizujWielomian( double wspNormalizacji ) const{
    Wielomian wNorma(*this);
    for (int i=0; i<=wNorma.pobierzStopien(); i++){
         wNorma.wspolczynniki.at(i) = wNorma.wspolczynniki.at(i)/wspNormalizacji;
         //cout<<"-a"<<i<<"="<<wPrzeciwny[i];
    }
    return wNorma;
}
 

//============================================================================== 
/**  funkcja wyznaczająca pierwiastki wielomianu metodą Bairstowa
  *  
  *      @param dokladnosc - okreslenie dokladnosci metody
  *      @param p0 - warunek poczatkowy
  *      @param q0 - warunek poczatkowy
  *      @return pierwiastki wielomianu
  */
vector<complex<double> > Wielomian :: pierwiastkiB( double dokladnosc, double p0, double q0) const{
    int liczbaIteracji = 0,
        sumaIteracji = 0;
    double pKolejne = p0,   //zapisanie warunku początkowego
           qKolejne = q0,   //zapisanie warunku początkowego
            A0=1, A1=1,     
            A0dp, A1dp,
            A0dq, A1dq;
    double dzielnik[3] = {1, -pKolejne, -qKolejne}, //tablica do stworzenie wielomianu x^2 - px - q
            x[2] = {1, 0},  //tablica do stworzenie wielomianu x
            detA;
    Wielomian wReszta,  //deklaracje wielomianów
              wQn2,
              wQn2x,
              wX(1, &x[0]), // stworzenie wielomianu x
              wDzielnik(2, &dzielnik[0]), // stworzenie wielomianu x^2 - px - q
              wThis(*this);     //stworzenie wielomianu kopii (*this)
    complex<double> pierw1, pierw2, delta;     
    vector<complex<double> > pierwiastki;   //deklaracja zwracanego vectora pierwiastkow
    
    //cout<< endl << "w(*this) = "; wThis.wypisz();
    
    //--------------------------------------------------------------------------
    // główna pętla metody - dopóki stopien wielomianu jest większy od 1
    //--------------------------------------------------------------------------
    while (wThis.pobierzStopien()>=2){  //pętla dopóki stopien wielomianu W większy od 1
        
        //----------------------------------------------------------------------
        // pętla wyznaczająca współczynniki wielomianu x^2 - px - q
        //----------------------------------------------------------------------
        while (abs(A0)>dokladnosc || abs(A1)>dokladnosc){   //warunek stopu
            //------------------------------------------------------------------
            // wyznaczenie wielomianu x^2 - px - q
            //------------------------------------------------------------------
            wDzielnik[1] = -pKolejne;   //zmiana parametrów dzielnika x^2 - px -q
            wDzielnik[0] = -qKolejne;   
            //cout<< endl << "wDzielnik = "; wDzielnik.wypisz();
            //cout<< endl << "W = "; wThis.wypisz();
            
            //------------------------------------------------------------------
            // wyznaczenie A1, A0 i ich pochodnych
            //------------------------------------------------------------------
            wReszta = wThis % wDzielnik;    //wyznaczenie reszty z dzielenia W/x^2-px-q
            //cout<< endl << "wReszta = "; wReszta.wypisz();
            //cout << endl << " stopien = " <<wReszta.pobierzStopien();
            wQn2 = wThis / wDzielnik;   //wyznaczenie wielomianu Qn-2
            //cout<< endl << "wQn2 = "; wQn2.wypisz();
            wQn2x = wQn2 * wX;      //wyznaczenie wielomianu xQn-2
            //cout<< endl << "wQn2x = "; wQn2x.wypisz();
            if (wReszta.pobierzStopien() == -1 ){   //mogło być dzielenie bez reszty
                A0 = 0.0;   //trzeba wpisać zera w parametry A0, A1
                A1 = 0.0;
            }else if(wReszta.pobierzStopien() == 0){ //albo reszta zerowego stopnia
                A0 = wReszta[0]; 
                A1 = 0.0;   //w A1 trzeba wpisać 0
            }else{  //reszta jest wielomianem stopnia 1
                A0 = wReszta[0];    //ukonkretnienie wsp A1 i A0
                A1 = wReszta[1];
            }
            //cout<< endl <<"A0 = "<<A0<<endl;
            //cout<< "A1 = "<<A1<<endl;
            wReszta = wQn2 % wDzielnik; //wyznaczenie reszty z dzielenia Qn-2/x^2-px-q
            //cout<< endl << "wReszta = "; wReszta.wypisz();
            if (wReszta.pobierzStopien() == -1 ){  //mogło być dzielenie bez reszty
                A0dq = 0.0;
                A1dq = 0.0;
            }else if(wReszta.pobierzStopien() == 0){ //albo reszta zerowego stopnia
                A0dq = wReszta[0];
                A1dq = 0.0;
            }else{  //reszta jest wielomianem stopnia 1
                A0dq = wReszta[0];
                A1dq = wReszta[1];
            }
            //cout<< endl <<"A0dq = "<< A0dq <<endl;
            //cout<< "A1dq = "<< A1dq <<endl;
            wReszta = wQn2x % wDzielnik; //wyznaczenie reszty z dzielenia xQn-2/x^2-px-q
            //cout<< endl << "wReszta = "; wReszta.wypisz();
            if (wReszta.pobierzStopien() == -1 ){ //mogło być dzielenie bez reszty
                A0dp = 0.0;
                A1dp = 0.0;
            }else if(wReszta.pobierzStopien() == 0){ //albo reszta zerowego stopnia
                A0dp = wReszta[0];
                A1dp = 0.0;
            }else{  //reszta jest wielomianem stopnia 1
                A0dp = wReszta[0];
                A1dp = wReszta[1];
            }
            //cout<< endl <<"A0dp = "<< A0dp <<endl;
            //cout<< "A1dp = "<< A1dp <<endl;
            
            //------------------------------------------------------------------
            // wyznaczenie kolejnych wartości p i q
            //------------------------------------------------------------------
            detA = A0dp*A1dq - A1dp*A0dq;   //obliczenie wyznacznika macierzy pochodnych cząstkowych AO i A1
            pKolejne -= (A1dq*A0 - A1dp*A1)/detA;   //wyznaczenie kolejnej wartosci p
            qKolejne -= (-A0dq*A0 + A0dp*A1)/detA;  //wyznaczenie kolejnej wartosci q
            //cout<< endl <<"pKolejne = "<< pKolejne <<endl;
            //cout<< "qKolejne = "<< qKolejne <<endl;
            liczbaIteracji++;
        }  
        //----------------------------------------------------------------------
        // obliczenie pierwiastków dwumianu x^2-px-q
        //----------------------------------------------------------------------
        delta = pKolejne*pKolejne + 4*qKolejne;  //obliczenie delty
        //cout << endl << "delta = " << delta <<endl << sqrt(delta);
        pierw1 = (static_cast<complex<double> >(pKolejne) - sqrt(delta))/2.0;   //obliczenie pierwiastka 1
        pierw2 = (static_cast<complex<double> >(pKolejne) + sqrt(delta))/2.0;   //obliczenie pierwiastka 2
        cout<< endl << "liczba iteracji = " << liczbaIteracji<<endl;
        cout<< "pierwiastek1 = " <<pierw1 <<endl;
        cout<< "pierwiastek2 = " <<pierw2 <<endl;
        pierwiastki.push_back(pierw1);  //dopisanie pierwiastka 1 do vectora pierwiastkow
        pierwiastki.push_back(pierw2);  //dopisanie pierwiastka 1 do vectora pierwiastkow
        wDzielnik[1] = -pKolejne;   //aktualizacja wielomianu x^2 - px - q
        wDzielnik[0] = -qKolejne;
        //wDzielnik = Wielomian(2, &dzielnik[0]);
        //cout<< endl << "wDzielnik = "; wDzielnik.wypisz();
        wThis = wThis / wDzielnik;  //deflacja wielomianu W wielomianem x^2 - px - q
        //cout<< endl << "wThis = "; wThis.wypisz();
        
        //----------------------------------------------------------------------
        // obliczenie pierwiastków czynnika liniowego
        //----------------------------------------------------------------------
        if (wThis.pobierzStopien() ==  1 ){ // W jest stopnia 1 tzn (*this) był stopnia nieparzystego
            pierw1 = -wThis[0]/wThis[1];    // obliczenie pierwiastka czynnika linowego
            cout<< endl << "pierwiastek = " <<pierw1 <<endl;
            pierwiastki.push_back(pierw1);
        }/*else if (wThis.pobierzStopien() == 2){
            complex<double> delta = pKolejne*pKolejne + 4*qKolejne;
            cout << endl << "delta = " << delta <<endl << sqrt(delta);
            complex<double> pierw1 = (static_cast<complex<double> >(pKolejne) - sqrt(delta))/2.0;
            complex<double> pierw2 = (static_cast<complex<double> >(pKolejne) + sqrt(delta))/2.0;
            cout<< endl << "pierw1 = " <<pierw1 <<endl;
            cout<< endl << "pierw2 = " <<pierw2 <<endl;
            pierwiastki.push_back(pierw1);
            pierwiastki.push_back(pierw2);
        }*/
        //----------------------------------------------------------------------
        // przygotowanie do wyznaczenie kolejnego pierwiastka
        //----------------------------------------------------------------------
        sumaIteracji += liczbaIteracji;
        liczbaIteracji = 0;
        A0 = 1;     
        A1 = 1;
        pKolejne = p0;
        qKolejne = q0;
    }
    cout<<endl<<"suma iteracji = "<<sumaIteracji<<endl;
    return pierwiastki;
}
    
//============================================================================== 
/**  funkcja wyznaczająca pierwiastki wielomianu metodą Laguerre'a
  *  
  *      @param dokladnosc - okreslenie dokladnosci metody
  *      @param a0 - warunek poczatkowy
  *      @return pierwiastki wielomianu
  */
vector<complex<double> > Wielomian :: pierwiastkiL( double dokladnosc, complex<double> a0) const{
    int liczbaIteracji = 0,
        sumaIteracji = 0,
        n = (*this).pobierzStopien();   //pobranie stopnia wielomianu
    complex<double> a(0.0, 0.0),    //deklaracje liczb zespolonych
                    mianownikPlus(0.0, 0.0),
                    mianownikMinus(0.0, 0.0),
                    xKolejne(0.0, 0.0),
                    wartoscH(0.0, 0.0),
                    wartoscG(0.0, 0.0);
    vector<complex<double> > pierwiastki;   //deklaracja zwracanego vectora pierwiastkow
    Wielomian wPrim, wBis, wTemp((*this));  //wielomiany pomocnicze (wTemp = (*this) )
    double dzielnik[3] = {1};   //tablica do tworzenia wielomianu dzielnika
    
    //--------------------------------------------------------------------------
    // główna pętla metody - po ilości pierwiastkó wielomianu
    //--------------------------------------------------------------------------
    for (int i=0; i<n; i++){    //pętla po ilości pierwiastków
        a = a0;     //przypisanie warunku początkowego
        xKolejne = a;   //ustalenie x początkowego
        //----------------------------------------------------------------------
        // pętla wyznaczająca pierwiastek wielomianu xKolejne -= a
        //----------------------------------------------------------------------
        do{
            //wTempStopien = wTemp.pobierzStopien();
            
            //------------------------------------------------------------------
            // obliczenie wartości G(xKolejne) i H(xKolejne)
            //------------------------------------------------------------------
            wPrim = wTemp.pochodna(1);  //wyznaczenie pierwszej pochodnej wielomianu tymczasowego
            wBis = wPrim.pochodna(1);   //wyznaczenie drugiej pochodnej wielomianu tymczasowego
            wartoscG = wPrim(xKolejne)/wTemp(xKolejne); //wyznaczenie G(xKolejne)
            wartoscH = wartoscG*wartoscG - wBis(xKolejne)/wTemp(xKolejne); //wyznaczenie H(xKolejne)
            
            
            //------------------------------------------------------------------
            // obliczenie dwóch wersji mianownika w wyrażeniu na a
            //------------------------------------------------------------------
            mianownikPlus = wartoscG + sqrt( static_cast<double>((n - 1))*(static_cast<double>(n)*wartoscH - wartoscG*wartoscG ));
                                            //wyznaczenie mianownika z plusem w wyrażeniu na a
            mianownikMinus = wartoscG - sqrt( static_cast<double>((n - 1))*(static_cast<double>(n)*wartoscH - wartoscG*wartoscG ));
                                            //wyznaczenie mianownika z minusem w wyrażeniu na a
            
            //------------------------------------------------------------------
            // wyznaczenie poprawnej wartości a i xKolejne = xKolejne - a
            //------------------------------------------------------------------
            if( abs(mianownikPlus) >= abs(mianownikMinus) ){    //mianownikPlus większy co do modułu
                a = static_cast<double>(n)/mianownikPlus;   //stostujemy go do wyznaczenia a
            }else{  //mianownikMinus większy co do modułu
                a = static_cast<double>(n)/mianownikMinus;  //stostujemy mianownikMinus
            }
            xKolejne -= a;  //wyznaczamy kolejne przybliżenie x (pierwiastka wielomianu)
            liczbaIteracji++;   //zwiększamy licznik iteracji
        }while( abs(a) >= dokladnosc && ( abs(wTemp(xKolejne)) > 0));     //warunek stopu na wartość modułu a
        
        //----------------------------------------------------------------------
        // wyznaczenie poprawnej wartości a i xKolejne = xKolejne - a
        //----------------------------------------------------------------------
        pierwiastki.push_back(xKolejne);    //dołożenie rozwiązania do wektora rozwiązan
        //iteracje.push_back(liczbaIteracji++);
        //cout<<endl<<"liczba iteracji = "<<liczbaIteracji<<endl;
        //cout<<"pierwiastek = "<<xKolejne;   //wypisanie pierwiastka
        sumaIteracji += liczbaIteracji;
        liczbaIteracji = 0; //wyzerowanie liczby iteracji
        
        //----------------------------------------------------------------------
        // deflacja wielomianu w zależności od charakteru pierwiastka
        //----------------------------------------------------------------------
        if( xKolejne.imag() == 0 ){     //pierwiastek jest rzeczywisty
            dzielnik[1] = -xKolejne.real();     // dodanie elementu -xKolejne do tablicy tworzącej wielomian dzielnikowy
            //Wielomian w9 = Wielomian(1, &dzielnik[0]);
            wTemp = wTemp/Wielomian(1, &dzielnik[0]);   //deflacja czynnikiem (x-xKolejne)
        }else{      //pierwiastek jest zespolony c + dj
            dzielnik[1] = -2.0*xKolejne.real();     //dodanie elementu -2c*x
            dzielnik[2] = xKolejne.imag()*xKolejne.imag() + xKolejne.real()*xKolejne.real(); //dodanie elementu c^2+d^2
            //Wielomian w7 = Wielomian(1, &dzielnik[0]);
            wTemp = wTemp/Wielomian(2, &dzielnik[0]);   //deflacja czynnikiem (x^2-2cx+c^2+d^2)
            //xKolejne.imag() =  -xKolejne.imag();    //stworzenie pierwiastka sprzężonego
			complex<double> z(xKolejne.real(), -xKolejne.imag());
            pierwiastki.push_back(z);    //zapisanie pierwiastka sprzężonego do wektora rozwiązan
            //cout<<endl<<"pierwiastek sprzezony = "<<xKolejne;   //wypisanie pierw sprzeżonego
            i++;    //szukamy jednego pierwiastka mniej, bo znaleźliśmy sprzężoną parę zespoloną
        }
        //cout<< endl <<"wTemp = ";
        //wTemp.wypisz();
        //cout<< endl;
    }
    //cout<<endl<<"suma iteracji = "<<sumaIteracji<<endl;     
    return pierwiastki;
}
 
//============================================================================== 
/** publiczna funkcja składowa klasy Wielomian wypisująca wielomian na ekran
  *     
  *     @see operator<<(ostream &cout, const Wielomian & w)
  */
 void Wielomian :: wypisz() const {
     int stopien = (*this).pobierzStopien();
     if ( stopien < 0){ 
            cout<<"Wielomian pusty";
     }else{
        for(int i = 0; i <= stopien; i++){  //pętla po ilości wspolczynnikow
            double wspObecny = (*this).wspolczynniki.at(i);
            if (wspObecny == 0){    //jesli wsp==0 to nie wypisujemy
                continue;
            }else if (i>0 && wspObecny>0){  //wsp dodatni i nie przy najwyzszej potedze
                //double wspNastepny = w.wspolczynniki.at(i+1);
                cout << " + ";
                cout<< wspObecny << "x^" << stopien-i;
            }else if (i>0 && wspObecny<0){  //wsp ujemny i nie przy najwyzeszej potedze
                cout << " - ";
                cout<< abs(wspObecny) << "x^" << stopien-i;            
            }else{  //wsp przy najwyzszej potedze
                cout<< wspObecny << "x^" << stopien-i;
            }
        }
     }
 }
 
 
//============================================================================== 
/** publiczna funkcja składowa klasy Wielomian zwracająca stopien wielomianu
  *     
  *     @return stopien wielomianu
  */
 int Wielomian :: pobierzStopien() const{
     return stopien;
 }

//============================================================================== 
/** funkcja zwracająca wspołczynnik wielomianu przy potedze wspIndex. 
  *
  *     @param wspIndex - indeks wspolczynnika wielomianu (wykładnik potęgi) który ma być
  *                pobrany
  *     @return współczynnik przy potędze wspIndex
  */
double Wielomian :: pobierzWsp( unsigned int wspIndex) const{
     return this->wspolczynniki.at(this->stopien - wspIndex);
 }
 
 
//============================================================================== 
/** publiczna funkcja składowa klasy Wielomian zwracająca iterator do poczatku 
  * wektora wspolczynnikow
  *     
  *     @return iterator
  */
 std::vector<double>::iterator Wielomian::pobierzIteratorPoczatek(){
     return wspolczynniki.begin();
 }
    
//============================================================================== 
/** publiczna funkcja składowa klasy Wielomian zwracająca iterator do poczatku 
  * wektora wspolczynnikow
  *     
  *     @return iterator
  */
 std::vector<double>::iterator Wielomian::pobierzIteratorKoniec(){
     return wspolczynniki.end();
 }
 //-----------------------------------------------------------------------------
 //-------------- KONIEC [klasa wielomian] -------------------------------------
 //-----------------------------------------------------------------------------

 
 
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
//++++++++++++++ POCZĄTEK [deklaracji funkcji pomocniczych] ++++++++++++++++++++
//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

//============================================================================== 
/** funkcja przeładowanego operatora rownosci wielomianow.
  *
  *     @param w1  -  składnik pierwszy 
  *     @param w2  -  składnik drugi
  *     @return true - jesli wielomiany sa sobie rowne
  */
 bool operator== ( const Wielomian &w1, const Wielomian &w2 ){
     if(w1.stopien != w2.stopien) return false;
     for(int i=0; i<=w1.stopien; i++){
         if(w1.wspolczynniki.at(i) != w2.wspolczynniki.at(i)) return false;
     }
     return true;
 }
 
 
 //============================================================================== 
/** funkcja przeładowanego operatora nierownosci wielomianow.
  *
  *     @param w1  -  składnik pierwszy 
  *     @param w2  -  składnik drugi
  *     @return true - jesli wielomiany sa rozne
  */
 bool operator!= ( const Wielomian &w1, const Wielomian &w2 ){
     if(w1.stopien != w2.stopien) return true;
     for(int i=0; i<=w1.stopien; i++){
         if(w1.wspolczynniki.at(i) != w2.wspolczynniki.at(i)) return true;
     }
     return false;
 }
 

//============================================================================== 
/** funkcja przeładowanego operatora wypisanie wielomianu do strumienia
  *
  *     @param cout - referencja do strumienia wyjściowego 
  *     @param w - wielomian do wypisania  
  *     @return &cout - referencja do strumienia
  */
ostream &operator<<(ostream &cout, const Wielomian & w) {
    int stopien = w.pobierzStopien();
    if ( stopien < 0){
        cout<<"Wielomian pusty";
    }else{
        for(int i = 0; i <= stopien; i++){
            double wspObecny = w.wspolczynniki.at(i);
            if (wspObecny == 0){
                continue;
            }else if (i>0 && wspObecny>0){
                //double wspNastepny = w.wspolczynniki.at(i+1);
                cout << " + ";
                cout<< wspObecny;
                if(i != stopien) cout<<"x^"<<stopien-i;
            }else if (i>0 && wspObecny<0){
                cout << " - ";
                cout<< abs(wspObecny);
                if(i != stopien) cout<<"x^"<<stopien-i;
            }else{
                cout<< wspObecny;
                if(i != stopien) cout<<"x^"<<stopien-i;
            }
        }
    }
    return cout;
}

 
//============================================================================== 
/** funkcja przeładowanego operatora dodawania dwuargumentowego.
  *
  *     @param w1  -  składnik pierwszy 
  *     @param w2  -  składnik drugi
  *     @return wielomian będący sumą w1 i w2
  */
 Wielomian  operator+( const Wielomian & w1, const Wielomian & w2){
     int w1Stopien = w1.pobierzStopien(),
         w2Stopien = w2.pobierzStopien();
     Wielomian wSuma;
    //cout<<"w1Stopien"<<w1Stopien<<"w2Stopien"<<w2Stopien;
     if( w1Stopien >= w2Stopien ){
         wSuma = w1;
         //cout<<endl<<"wSuma przed:";
         //wSuma.wypisz();
         //cout<<endl;
         for(int i=0; i<=w2Stopien; i++){
             wSuma.wspolczynniki.at( w1Stopien - i ) += w2.wspolczynniki.at( w2Stopien - i );
             //cout<<"w2 = "<<w2[i]<<endl;
             //cout<<"wSuma = "<<wSuma[i]<<endl;
         }
     }else{
        wSuma = w2;
        //cout<<endl<<"wSuma przed:";
        //wSuma.wypisz();
        //cout<<endl;
        for(int i=0; i<=w1Stopien; i++){
             wSuma.wspolczynniki.at( w2Stopien - i ) += w1.wspolczynniki.at( w1Stopien - i);
             //cout<<w1[i];
        }
     }
     //cout<< "wSuma po:";
     //wSuma.wypisz();
     //cout<<endl;
     wSuma.usunZera();
     return wSuma;  
 }
 
//============================================================================== 
/** funkcja przeładowanego operatora odejmowania jednoargumentowego (odwrócenie 
  * wielomianu)
  *
  *     @param w  -  wielomian do odwrócenia
  *     @return wielomian odwrócony (-w)
  */
 Wielomian operator-( const Wielomian & w){
     //cout<<"wPrzeciwny przed";
     Wielomian wPrzeciwny(w);
     //wPrzeciwny.wypisz();
     //cout<<endl;
     for (int i=0; i<=w.pobierzStopien(); i++){
         wPrzeciwny.wspolczynniki.at(i) = -w.wspolczynniki.at(i); 
         //cout<<"-a"<<i<<"="<<wPrzeciwny[i];
     }
     //cout<<"wPrzeciwny po";
     //wPrzeciwny.wypisz();
     //cout<<endl;
     return wPrzeciwny;
 }
 
//============================================================================== 
/** funkcja przeładowanego operatora odejmowania dwuargumentowego
  *
  *     @param w1  -  składnik pierwszy 
  *     @param w2  -  składnik drugi
  *     @return wielomian będący różnicą w1-w2
  */
 Wielomian  operator-( const Wielomian & w1, const Wielomian & w2){
     int w1Stopien = w1.pobierzStopien(),
                  w2Stopien = w2.pobierzStopien();
     Wielomian wSuma;
     //cout<<endl<<"wSuma przed:";
         //wSuma.wypisz();
         //cout<<endl;
     //cout<<"w1Stopien"<<w1Stopien<<"w2Stopien"<<w2Stopien;
     if( w1Stopien >= w2Stopien ){
         wSuma = w1;
         //cout<<endl<<"wSuma przed:";
         //wSuma.wypisz();
         //cout<<endl;
         for(int i=0; i<=w2Stopien; i++){
             wSuma.wspolczynniki.at( w1Stopien-i) -= w2.wspolczynniki.at( w2Stopien-i);
             //cout<<"w2 = "<<w2[i]<<endl;
             //cout<<"wSuma = "<<wSuma[i]<<endl;
         }
     }else{
        wSuma = -w2;
        //cout<<endl<<"wSuma przed:";
        //wSuma.wypisz();
        //cout<<endl;
        for(int i=0; i<=w1Stopien; i++){
             wSuma.wspolczynniki.at( w2Stopien-i) += w1.wspolczynniki.at( w1Stopien-i);
             //cout<<"w2 = "<<w1[i]<<endl;
             //cout<<"wSuma = "<<wSuma[i]<<endl;
        }
     }
     //cout<< "wSuma po:";
     //wSuma.wypisz();
     //cout<<endl;
     wSuma.usunZera();
     return wSuma;  
 }
 
//============================================================================== 
/** funkcja przeładowanego operatora mnożenia
  *
  *     @param w1  -  czynnik pierwszy 
  *     @param w2  -  czynnik drugi
  *     @return wielomian iloczynem w1*w2
  */
 Wielomian operator*( const Wielomian & w1, const Wielomian & w2) {
     /*
     if(!w1 || !w2){
        return 0.0;
     }
      */   
     int w1Stopien = w1.pobierzStopien(), 
         w2Stopien = w2.pobierzStopien();
     Wielomian wIloczyn( w1Stopien + w2Stopien + 1, 0.0 );
                       
     for(int i=0; i <= w1Stopien; ++i){
         for(int j=0; j <= w2Stopien; ++j){
            //wIloczyn[i+j] += w1[i] * w2[j];
            wIloczyn.wspolczynniki.at(w1Stopien+w2Stopien+1-i-j) += 
                     w1.wspolczynniki.at(w1Stopien-i) * w2.wspolczynniki.at(w2Stopien-j);
            //wIloczyn.wspolczynniki.at(i+j) += 
                     //w1.wspolczynniki.at(i) * w2.wspolczynniki.at(j);
         }
     }   
     wIloczyn.usunZera();
     return wIloczyn;
 }
 
//============================================================================== 
/** funkcja przeładowanego operatora dzielenia
  *
  *     @param w1  -  dzielna pierwszy 
  *     @param w2  -  dzielnik drugi
  *     @return wielomian będący ilorazem w1/w2
  */
 Wielomian operator/( const Wielomian & w1, const Wielomian & w2) {
    /*
    if(!wiel1 || !wiel2)
        return 0.0;
    */           
    Wielomian wReszta(w1), wIloraz, x;
    int w1Stopien = w1.pobierzStopien(), 
        w2Stopien = w2.pobierzStopien();
    wIloraz.stopien = -1;
    if(w1Stopien >= w2Stopien){        
        while( wReszta.pobierzStopien() >= w2Stopien ){
            //cout<<"preszta = ";
            x.wspolczynniki.erase( x.wspolczynniki.begin(), x.wspolczynniki.end() );
            //wReszta.wypisz();
            //x.wspolczynniki.push_back( wReszta[wReszta.pobierzStopien()] / w2[w2Stopien] );
            x.wspolczynniki.push_back( wReszta.wspolczynniki.at(0) / w2.wspolczynniki.at(0) );
            //cout << endl <<" wspol = " << x.wspolczynniki.at(0) << endl;
            x.wspolczynniki.insert( x.wspolczynniki.end(), wReszta.pobierzStopien()-w2Stopien, 0.0 );
            /*for(int i=0; i<wReszta.pobierzStopien()-w2Stopien; i++){
                x.wspolczynniki.push_back(0.0);
                cout<<x.wspolczynniki.at(i+1);
            }
             */
            x.stopien = wReszta.pobierzStopien()-w2Stopien;
            //cout << endl << " x = ";
            //x.wypisz();
            
            wReszta -= (x * w2);
            //cout<< endl << "reszta = ";
            //wReszta.wypisz();
            //cout << endl;
            wIloraz.wspolczynniki.push_back(x.wspolczynniki.at(0));
            wIloraz.stopien++;
        }
                       
        return wIloraz;
    }else{
        return 0.0;
    }
}
 
//============================================================================== 
/** funkcja przeładowanego operatora modulo %
  * zwraca reszte z dzielenia wielomianu
  *
  *     @param w1  -  dzielna 
  *     @param w2  -  dzielnik 
  *     @return reszta z dzielenia w1/w2
  */
 Wielomian operator%( const Wielomian & w1, const Wielomian & w2) {
    /*
    if(!wiel1 || !wiel2)
        return 0.0;
    */           
    Wielomian wReszta(w1), x;
    int w1Stopien = w1.pobierzStopien(), 
        w2Stopien = w2.pobierzStopien();
    if(w1Stopien >= w2Stopien){        
        while( wReszta.pobierzStopien() >= w2Stopien ){
            //cout<<"preszta = ";
            x.wspolczynniki.erase( x.wspolczynniki.begin(), x.wspolczynniki.end() );
            //wReszta.wypisz();
            //x.wspolczynniki.push_back( wReszta[wReszta.pobierzStopien()] / w2[w2Stopien] );
            x.wspolczynniki.push_back( wReszta.wspolczynniki.at(0) / w2.wspolczynniki.at(0) );
            //cout << endl <<" wspol = " << x.wspolczynniki.at(0) << endl;
            x.wspolczynniki.insert( x.wspolczynniki.end(), wReszta.pobierzStopien()-w2Stopien, 0.0 );
            /*for(int i=0; i<wReszta.pobierzStopien()-w2Stopien; i++){
                x.wspolczynniki.push_back(0.0);
                cout<<x.wspolczynniki.at(i+1);
            }
             */
            x.stopien = wReszta.pobierzStopien()-w2Stopien;
            //cout << endl << " x = ";
            //x.wypisz();
            
            wReszta -= (x * w2);
            //cout<< endl << "reszta = ";
            //wReszta.wypisz();
            //cout << endl;
        }
                       
        return wReszta;
    }else{
        return wReszta;
    }
}
//------------------------------------------------------------------------------
//-------------- KONIEC [funkcje pomocnicze] -----------------------------------
//------------------------------------------------------------------------------

 
